package com.smart.service.oss;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.qiniu.common.QiniuException;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.util.Auth;
import com.smart.common.entities.constant.SmartConstant;
import com.smart.common.entities.file.UploadBody;
import com.smart.common.entities.file.UploadResult;
import com.smart.common.exception.SmartException;
import com.smart.manager.system.repository.ConfigRepository;
import com.smart.utils.ContentTypeUtil;
import com.smart.utils.FileUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
import java.util.Set;

/**
 * 七牛云文件处理程序
 *
 * @author Administrator
 * @date 2022/09/09
 */

@Component
@RequiredArgsConstructor
public class QiNiuYunFileHandler {

    private final ConfigRepository configRepository;


    /**
     * 获取七牛云配置参数对象
     *
     * @return {@code ConfigAssembler.QiNiuYun}
     */
    private JSONObject readConfig() {
        JSONObject jsonObject = configRepository.readCache(SmartConstant.QINIUYUN_OSS_CFG);
        Set<String> mustKeys = Set.of("accessKey", "secretKey", "bucket", "readPath");
        Assert.isTrue(jsonObject.keySet().containsAll(mustKeys), "七牛云参数配置参数必须包含以下参数字段:" + mustKeys);
        Assert.isTrue(ObjectUtil.isAllNotEmpty(jsonObject), "七牛云参数配置存在空配置字段");
        return configRepository.readCache(SmartConstant.QINIUYUN_OSS_CFG);

    }


    private String getUploadToken(JSONObject config) {
        //创建七牛云认证对象
        Auth auth = Auth.create(config.getString("accessKey"), config.getString("secretKey"));
        //获取上传的身份令牌
        return auth.uploadToken(config.getString("bucket"));
    }


    /**
     * 得到上传管理器
     *
     * @return {@link UploadManager}
     */
    private UploadManager getUploadManager() {
        Configuration cfg = new Configuration(Region.autoRegion());
        return new UploadManager(cfg);
    }


    /**
     * 得到上传结果
     *
     * @param newFileName 新文件名字
     * @param config      配置
     * @return {@link UploadResult}
     */
    private UploadResult getUploadResult(String newFileName, JSONObject config) {


        String url = config.getString("readPath").concat("/").concat(newFileName);
        return new UploadResult().setUid(StrUtil.uuid()).setName(newFileName).setUrl(url);
    }
    /**
     * 得到上传结果
     * @param newFileName 新文件名字
     * @param config      配置
     * @param fileName    原文件名称
     * @return {@link UploadResult}
     */
    private UploadResult getUploadResult(String newFileName, JSONObject config,String fileName) {
        String url = config.getString("readPath").concat("/").concat(newFileName);
        return new UploadResult().setUid(StrUtil.uuid()).setName(fileName).setUrl(url);
    }


    /**
     * 七牛云上传文件处理器
     *
     * @param file           文件
     * @param topFolder      顶级文件夹
     * @param fileNamePrefix 文件名前缀
     * @return {@code UploadResult}
     */
    public UploadResult uploadImg(MultipartFile file, String topFolder, String fileNamePrefix) {
        JSONObject config = this.readConfig();
        InputStream inputStream = null;

        try {
            assert file != null;
            String filename = file.getOriginalFilename();
            assert filename != null;
            String ext = filename.substring(filename.indexOf("."));
            // 设置新存储的文件名字

            String newFileName = FileUtils.getFileName(topFolder, ext, fileNamePrefix);
            inputStream = file.getInputStream();

            UploadManager uploadManager = getUploadManager();
            String upToken = getUploadToken(config);
            uploadManager.put(inputStream, newFileName, upToken, null, null);

            UploadResult uploadResult = new UploadResult();
            uploadResult.setName(filename).setUrl(config.getString("readPath").concat("/").concat(newFileName));

            return uploadResult;
        } catch (QiniuException ex) {
            throw new SmartException("上传七牛服务器异常" + ex.getMessage());
        } catch (IOException e) {
            throw new SmartException("读取文件IO流失败");
        } catch (Exception e) {
            throw new SmartException("上传异常:" + e.getMessage());
        } finally {


            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }


        }

    }

    /**
     * 七牛云文件对象上传
     *
     * @param file           文件
     * @param topFolder      顶级文件夹
     * @param fileNamePrefix 文件名前缀
     * @return {@code UploadResult}
     */
    public UploadResult uploadFile(MultipartFile file, String topFolder, String fileNamePrefix) {
        JSONObject config = this.readConfig();
        InputStream inputStream = null;

        try {
            assert file != null;
            String filename = file.getOriginalFilename();
            assert filename != null;
            String ext = filename.substring(filename.indexOf("."));
            // 设置新存储的文件名字
            String newFileName = FileUtils.getFileName(topFolder, ext, fileNamePrefix);
            inputStream = file.getInputStream();
            UploadManager uploadManager = getUploadManager();
            String upToken = getUploadToken(config);
            uploadManager.put(inputStream, newFileName, upToken, null, null);
            return getUploadResult(newFileName, config,filename);
        } catch (QiniuException ex) {

            throw new SmartException("上传七牛服务器异常" + ex.getMessage());

        } catch (IOException e) {

            throw new SmartException("读取文件IO流失败");
        } catch (Exception e) {

            throw new SmartException("上传异常:" + e.getMessage());

        } finally {


            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }


        }


    }

    /**
     * 七牛云 Base64上传文件
     *
     * @param dto            dto
     * @param topFolder      顶级文件夹
     * @param fileNamePrefix 文件名前缀
     * @return {@code UploadResult}
     */
    public UploadResult uploadFile(UploadBody.Base64 dto, String topFolder, String fileNamePrefix) {
        JSONObject config = readConfig();
        //解析BASE64字符串内的文件类型
        String contentType = dto.getBase64().substring(0, dto.getBase64().indexOf(",")).replace("data:", "").replace(";base64", "");
        String ext = Optional.of(ContentTypeUtil.getExt(contentType)).orElse(".data");
        String newFileName = FileUtils.getFileName(topFolder, ext, fileNamePrefix);
        byte[] uploadBytes = FileUtils.base64StringToByte(dto.getBase64());
        UploadManager uploadManager = getUploadManager();
        String upToken = getUploadToken(config);
        try {
            uploadManager.put(uploadBytes, newFileName, upToken);
            return getUploadResult(newFileName, config);

        } catch (Exception e) {
            throw new SmartException("上传失败,BASE64字符串上传到七牛云失败");

        }

    }


    /**
     * 七牛云 Byte上传文件
     *
     * @param dto            dto
     * @param topFolder      顶级文件夹
     * @param fileNamePrefix 文件名前缀
     * @return {@code UploadResult}
     */
    public UploadResult uploadFile(UploadBody.ByteFile dto, String topFolder, String fileNamePrefix) {
        JSONObject config = readConfig();
        String s = ContentTypeUtil.getExt(dto.getContentType());
        String ext = StrUtil.isBlank(s) ? ".xlsx" : s;
        String newFileName = FileUtils.getFileName(topFolder, ext, fileNamePrefix);
        UploadManager uploadManager = getUploadManager();
        String upToken = getUploadToken(config);
        try {
            uploadManager.put(dto.getData(), newFileName, upToken);
            return getUploadResult(newFileName, config);
        } catch (Exception e) {
            throw new SmartException("上传失败,字节码上传到七牛云失败");

        }

    }
}
